route.ts•6.05 kB
import { createMcpHandler } from "@vercel/mcp-adapter";
import { z } from "zod";
const MOTION_API_KEY = process.env.MOTION_API_KEY;
async function fetchMotion(endpoint: string, options: RequestInit = {}) {
const res = await fetch(`https://api.usemotion.com/v1/${endpoint}`, {
...options,
headers: {
"Content-Type": "application/json",
"X-API-Key": MOTION_API_KEY!,
...(options.headers || {}),
},
});
if (!res.ok) throw new Error(`Motion API error: ${res.statusText}`);
return res.json();
}
const handler = createMcpHandler(
async (server) => {
server.tool(
"echo",
"description",
{
message: z.string(),
},
async ({ message }) => ({
content: [{ type: "text", text: `Tool echo: ${message}` }],
})
);
// Get Tasks
server.tool(
"getTasks",
"Get a list of tasks from Motion",
{},
async () => {
const tasks = await fetchMotion("tasks");
return {
content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }],
};
}
);
// Update Task
server.tool(
"updateTask",
"Update a task in Motion",
{
taskId: z.string(),
updates: z.object({
name: z.string().optional(),
description: z.string().optional(),
status: z.string().optional(),
project: z.string().optional(),
workspace: z.string().optional(),
deadline: z.string().optional(),
startDate: z.string().optional(),
duration: z.number().optional(),
// Add more fields as needed
}),
},
async ({ taskId, updates }) => {
const updated = await fetchMotion(`tasks/${taskId}`, {
method: "PATCH",
body: JSON.stringify(updates),
});
return {
content: [{ type: "text", text: JSON.stringify(updated, null, 2) }],
};
}
);
// Create Task
server.tool(
"createTask",
"Create a new task in Motion",
{
name: z.string(),
description: z.string().optional(),
status: z.string().optional(),
project: z.string().optional(),
workspace: z.string().optional(),
deadline: z.string().optional(),
startDate: z.string().optional(),
duration: z.number().optional(),
// Add more fields as needed
},
async ({ name, description, status, project, workspace, deadline, startDate, duration }) => {
const created = await fetchMotion("tasks", {
method: "POST",
body: JSON.stringify({ name, description, status, project, workspace, deadline, startDate, duration }),
});
return {
content: [{ type: "text", text: JSON.stringify(created, null, 2) }],
};
}
);
// Delete Task
server.tool(
"deleteTask",
"Delete a task in Motion",
{
taskId: z.string(),
},
async ({ taskId }) => {
const deleted = await fetchMotion(`tasks/${taskId}`, {
method: "DELETE",
});
return {
content: [{ type: "text", text: JSON.stringify(deleted, null, 2) }],
};
}
);
// Create Recurring Task
server.tool(
"createRecurringTask",
"Create a new recurring task in Motion",
{
name: z.string(),
description: z.string().optional(),
status: z.string().optional(),
project: z.string().optional(),
workspace: z.string().optional(),
cadence: z.string(), // e.g. 'daily', 'weekly', 'monthly', etc.
startDate: z.string().optional(),
endDate: z.string().optional(),
// Add more fields as needed
},
async ({ name, description, status, project, workspace, cadence, startDate, endDate }) => {
const created = await fetchMotion("recurring-tasks", {
method: "POST",
body: JSON.stringify({ name, description, status, project, workspace, cadence, startDate, endDate }),
});
return {
content: [{ type: "text", text: JSON.stringify(created, null, 2) }],
};
}
);
// List Recurring Tasks
server.tool(
"listRecurringTasks",
"List recurring tasks in Motion",
{
workspaceId: z.string().optional(),
},
async ({ workspaceId }) => {
const endpoint = workspaceId ? `recurring-tasks?workspaceId=${workspaceId}` : "recurring-tasks";
const tasks = await fetchMotion(endpoint);
return {
content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }],
};
}
);
// Delete Recurring Task
server.tool(
"deleteRecurringTask",
"Delete a recurring task in Motion",
{
recurringTaskId: z.string(),
},
async ({ recurringTaskId }) => {
const deleted = await fetchMotion(`recurring-tasks/${recurringTaskId}`, {
method: "DELETE",
});
return {
content: [{ type: "text", text: JSON.stringify(deleted, null, 2) }],
};
}
);
},
{
capabilities: {
tools: {
echo: {
description: "Echo a message",
},
getTasks: {
description: "Get a list of tasks from Motion",
},
updateTask: {
description: "Update a task in Motion",
},
createTask: {
description: "Create a new task in Motion",
},
deleteTask: {
description: "Delete a task in Motion",
},
createRecurringTask: {
description: "Create a new recurring task in Motion",
},
listRecurringTasks: {
description: "List recurring tasks in Motion",
},
deleteRecurringTask: {
description: "Delete a recurring task in Motion",
},
},
},
},
{
basePath: "",
verboseLogs: true,
maxDuration: 60,
}
);
export { handler as GET, handler as POST, handler as DELETE };